home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 436_01 / intempl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-07  |  12.7 KB  |  513 lines

  1. /*************************************************************************
  2.     Source file:  INTEMPL.C
  3.  
  4.     INCON template input handler.
  5.  
  6.     Compiler:  Borland Turbo C 2.01
  7.  
  8.     INCON source files and the object and library files created from
  9.     them are:
  10.         Copyright (c) 1993-94, Richard Zigler.
  11.     You may freely distribute unmodified source, object, and library
  12.     files, and incorporate them into your own non-commercial software,
  13.     provided that this paragraph and the program name and copyright
  14.     strings defined in INCON.C are included in all copies.
  15. *************************************************************************/
  16.  
  17. #include <conio.h>
  18. #include <ctype.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include "indefs.h"                            /* globals and definitions            */
  22. #include "incon.h"                            /* state definitions                    */
  23. #include "indecl.h"                            /* public utility routines            */
  24.  
  25. /**** Local Data ****/
  26.  
  27. typedef enum
  28.             {
  29.             T_INIT                        ,        /* initialize template string        */
  30.             F_CHAR                        ,        /* find first input slot            */
  31.             L_CHAR                        ,        /* find last input slot                */
  32.             N_CHAR                        ,        /* find next input slot                */
  33.             P_CHAR                        ,        /* find previous input slot        */
  34.             N_WORD                        ,        /* find next input word                */
  35.             P_WORD                        ,        /* find previous input word        */
  36.             S_WORD                        ,        /* find start of current word        */
  37.             E_WORD                        ,        /* find end of current word        */
  38.             T_WIPE                        ,        /* clear template                        */
  39.             T_STRIP                        ,        /* strip delimiters                    */
  40.             }                TEMPL_OP        ;        /* template opcodes                    */
  41.  
  42. typedef enum
  43.             {
  44.             MIX_DELIM                    ,        /* template delimiter                */
  45.             MIX_ALPHA                    ,        /* alpha input slot                    */
  46.             MIX_UPPER                    ,        /* uppercase input slot                */
  47.             MIX_INTGR                    ,        /* integer input slot                */
  48.             }                TEMPL_CHAR    ;        /* template characters                */
  49.  
  50. /**** Local Routines ****/
  51.  
  52. static int near pascal    TemplateFix
  53.                 (
  54.                 TEMPL_OP        Op,                /* operation requested                */
  55.                 int            Pos                /* position in source string        */
  56.                 )                ;
  57.  
  58. /***********************************************************************/
  59.  
  60. int pascal hTemplateField( STATES State, register int Pos )
  61. {
  62. register int        work;                        /* integer-size working storage    */
  63.             BFLAG        match;                    /* character match flag                */
  64.  
  65. switch( State )
  66.     {
  67.     case stError:
  68.         break;
  69.  
  70.     case stQuit:                                /* [Enter] -- end input                */
  71.  
  72.         if ( strchr( OutStr, Fill ) )
  73.             Chr = -1;
  74.         else if ( !(Chr == K_PLUS || Chr == K_MINUS) )
  75.             Chr = 0;
  76.         if ( Flags.Strip )
  77.             TemplateFix( T_STRIP, 0 );
  78.         More = NO;
  79.         break;
  80.  
  81.     case stInit:                                /* field initialization                */
  82.  
  83.         if ( DisplayStr != NULL )
  84.             Pos = TemplateFix( T_INIT, 0 );
  85.         break;
  86.  
  87.     case stFieldClear:                        /* [Esc] -- clear field or exit    */
  88.  
  89.         if ( EscSet )
  90.             More = NO;
  91.         else
  92.             {
  93.             Pos = TemplateFix( T_WIPE, 0 );
  94.             ++Update;
  95.             }
  96.         break;
  97.  
  98.     case stDeleteCharLeft:                    /* [Backspace] -- delete left        */
  99.  
  100.         if ( !(Pos == TemplateFix( F_CHAR, 0  )) )
  101.             {
  102.  
  103.             /* if at last slot in template and not already vacant                */
  104.  
  105.             if (OutStr[Pos] != (char)Fill && Pos == TemplateFix(L_CHAR, 0))
  106.                 OutStr[Pos] = Fill;
  107.  
  108.             /* else if not at word boundary                                            */
  109.  
  110.             else if ( DisplayStr[Pos - 1] )
  111.                 {
  112.                 work = TemplateFix( E_WORD, Pos );
  113.                 --Pos;
  114.                 memcpy( OutStr + Pos, OutStr + Pos + 1, work - Pos );
  115.                 OutStr[work] = Fill;
  116.                 }
  117.  
  118.             /* else move to last slot in previous word and delete that        */
  119.  
  120.             else
  121.                 {
  122.                 Pos = TemplateFix( P_CHAR, Pos );
  123.                 OutStr[Pos] = Fill;
  124.                 }
  125.  
  126.             /* if hidden input, fix display here and flag move only            */
  127.  
  128.             if ( Flags.Hide )
  129.                 {
  130.                 PutCursor( Row, Col + Pos );
  131.                 putch( Fill );
  132.                 --Move;
  133.                 }
  134.             else
  135.                 ++Update;
  136.             }
  137.         break;
  138.  
  139.     case stMoveToStart:                        /* [Home] -- start of field        */
  140.  
  141.         work = Pos;
  142.         Pos = TemplateFix( F_CHAR, 0 );
  143.         goto __MinusMove;
  144.  
  145.     case stMoveCharLeft:                        /* [Left Arrow] -- move char lt    */
  146.  
  147.         work = Pos;
  148.         Pos = TemplateFix( P_CHAR, Pos );
  149.         goto __MinusMove;
  150.  
  151.     case stMoveCharRight:                    /* [Right Arrow] -- move char rt    */
  152.  
  153.         work = Pos;
  154.         Pos = TemplateFix( N_CHAR, Pos );
  155.         goto __PlusMove;
  156.  
  157.     case stMoveToEnd:                            /* [End] -- end of field            */
  158.  
  159.         work = Pos;
  160.         Pos = TemplateFix( L_CHAR, 0 );
  161.         goto __PlusMove;
  162.  
  163.     case stMoveWordLeft:                        /* [Ctrl Left] -- move word lt    */
  164.  
  165.         work = Pos;
  166.         Pos = TemplateFix( P_WORD, Pos );
  167.  
  168. __MinusMove:
  169. ;
  170.         if ( work != Pos )
  171.             --Move;
  172.         break;
  173.  
  174.     case stMoveWordRight:                    /* [Ctrl Right] -- move word rt    */
  175.  
  176.         work = Pos;
  177.         Pos = TemplateFix( N_WORD, Pos );
  178.  
  179. __PlusMove:
  180. ;
  181.         if ( work != Pos )
  182.             ++Move;
  183.         break;
  184.  
  185.     case stDeleteWordLeft:                    /* [Ctrl L] -- delete word left    */
  186.  
  187.         if ( !Flags.Hide && !(Pos == TemplateFix( F_CHAR, 0  )) )
  188.             {
  189.             if ( DisplayStr[Pos - 1] )        /* if within word                        */
  190.                 {
  191.                 work    = Pos;
  192.                 Pos    = TemplateFix( S_WORD, Pos );
  193.                 }
  194.             else                                    /* at word boundary                    */
  195.                 {
  196.                 Pos    = TemplateFix( P_WORD, Pos );
  197.                 work    = TemplateFix( E_WORD, Pos );
  198.                 }
  199.             memset( OutStr + Pos, Fill, work - Pos + 1 );
  200.             ++Update;
  201.             }
  202.         break;
  203.  
  204.     case stDeleteWordRight:                    /* [Ctrl R] -- delete word right    */
  205.  
  206.         if ( !Flags.Hide && !(Pos == TemplateFix( L_CHAR, 0  )) )
  207.             {
  208.             if ( !DisplayStr[Pos + 1] )                 /* if at word boundary    */
  209.                 Pos = TemplateFix( N_WORD, Pos );     /*  move to next word    */
  210.             work = TemplateFix( E_WORD, Pos );
  211.             memset( OutStr + Pos, Fill, work - Pos + 1 );
  212.             ++Update;
  213.             }
  214.         break;
  215.  
  216.     case stDeleteToEnd:                        /* [Ctrl End] -- clear to end        */
  217.  
  218.         if ( !(Pos == TemplateFix( L_CHAR, 0  )) )
  219.             {
  220.             TemplateFix( T_WIPE, Pos );
  221.             ++Update;
  222.             }
  223.         break;
  224.  
  225.     case stDeleteToStart:                    /* [Ctrl Home] -- clear to start    */
  226.  
  227.         if ( !(Pos == TemplateFix( F_CHAR, 0  )) )
  228.             {
  229.             Pos = TemplateFix( -(T_WIPE), Pos );
  230.             ++Update;
  231.             }
  232.         break;
  233.  
  234.     case stDeleteAtCursor:                    /* [Del] -- delete at cursor        */
  235.  
  236.         work = TemplateFix( E_WORD, Pos );
  237.         if ( work != Pos )
  238.             memcpy( OutStr + Pos, OutStr + Pos + 1, work - Pos );
  239.         OutStr[work] = Fill;
  240.         ++Update;
  241.         break;
  242.  
  243.     case stExitPlus:                            /* [Keypad +] -- special exit        */
  244.     case stExitMinus:                            /* [Keypad -] -- special exit        */
  245.  
  246.         /****
  247.             Treat these keys as exit requests in integer templates.
  248.             In alpha templates, convert to '+' or '-' and fall through
  249.             to the match state.
  250.         ****/
  251.  
  252.         if ( Flags.Type == INTGR )
  253.             {
  254.             hTemplateField( stQuit, 0 );
  255.             break;
  256.             }
  257.         else
  258.             Chr = (State == stExitPlus) ? '+' : '-' ;
  259.  
  260.     case stCharMatch:                            /* see if entry matches field        */
  261.  
  262.         match    = NO;
  263.         work    = DisplayStr[Pos];
  264.         if ( work )
  265.             {
  266.             switch( Flags.Type )
  267.                 {
  268.                 case UPPER:
  269. __Upper:
  270. ;
  271.                     Chr = toupper( Chr );    /* convert and fall through        */
  272.  
  273.                 case ALPHA:
  274. __Alpha:
  275. ;
  276.                     match =    Flags.Type == MIXED    ?        /* if mixed,            */
  277.                                  isalpha( Chr )        :        /* match alpha only    */
  278.                                 !iscntrl( Chr )        ;        /* else match all        */
  279.                     break;
  280.  
  281.                 case INTGR:
  282. __Integer:
  283. ;
  284.                     match = isdigit( Chr );
  285.                     break;
  286.  
  287.                 case MIXED:
  288.  
  289.                     if ( work == MIX_ALPHA )
  290.                         goto __Alpha;
  291.                     else if ( work == MIX_UPPER )
  292.                         goto __Upper;
  293.                     else
  294.                         goto __Integer;
  295.                 }                                    /* switch (Type)                        */
  296.             }                                        /* if (work)                            */
  297.         if ( match )
  298.             {
  299.             if ( InBegin )
  300.                 {
  301.                 hTemplateField( stFieldClear, 0 );
  302.                 PutCursor( Row, Col );
  303.                 cputs( OutStr );
  304.                 PutCursor( Row, Col + Pos );
  305.                 }
  306.          OutStr[Pos++] = Chr;
  307.             if ( Flags.Hide )
  308.                 putch( ' ' );
  309.             if ( !DisplayStr[Pos] )
  310.                 Pos = TemplateFix( N_CHAR, Pos );
  311.             ++Update;
  312.             }
  313.         else
  314.             State = stError;
  315.         break;
  316.     }                                                /* switch (State)                        */
  317. return( Pos );
  318. }                                                    /**** hTemplateField()            ****/
  319.  
  320. /*************************************************************************
  321.     TemplateFix()
  322.  
  323.     hTemplateField() calls on this routine to initialize template fields
  324.     and manage the cursor within them.  During initialization an image
  325.     of the input string passed from the caller is built in DisplayStr,
  326.     which is otherwise unused when the Template flag is set.  Each
  327.     "template delimiter" in the input string is represented by a zero
  328.     in DisplayStr; each "input slot" by a non-zero value coded to the
  329.     type of input expected.  During other calls, DisplayStr is scanned
  330.     according to the value passed in Op.  When a valid input slot is
  331.     found the index into DisplayStr is returned to hTemplateField(),
  332.     which uses that index, in turn, as an index into the template.
  333. *************************************************************************/
  334.  
  335. static int near pascal TemplateFix
  336. (
  337. TEMPL_OP                Op,                        /* operation requested                */
  338. register    int        Pos                        /* position in source string        */
  339. )
  340. {
  341. register    int        i;                            /* holds chars from InStr for        */
  342.                                                     /*  T_INIT; indexes DisplayStr    */
  343.                                                     /*  for other operations            */
  344. int                    display,                    /* display default input string?    */
  345.                         templ_type;                /* template type                        */
  346. TEMPL_CHAR            templ_char;                /* character type                        */
  347.  
  348. switch( Op )
  349.     {
  350.     case T_INIT:
  351.  
  352.         display        = Flags.Display;
  353.         templ_type    = Flags.Type;
  354.  
  355.         /****
  356.             Op == T_INIT == 0.  Since Op is now available, use
  357.             it to track whether any input slots are defined for
  358.             the template.  If, at the end of the for() loop below,
  359.             Op is still 0, the template contains no input slots
  360.             and is invalid.
  361.  
  362.             Note:  If the value of T_INIT is defined as other than
  363.             0, Op must be initialized to 0 prior to the for() loop.
  364.         ****/
  365.  
  366.         for ( Pos = 0 ; Pos < Width ; Pos++ )
  367.             {
  368.             i = LOBYTE(InStr[Pos]);
  369.             templ_char = MIX_DELIM;
  370.  
  371.             /****
  372.                 Alpha and upper fields match on any alpha-numeric
  373.                 character, including punctuation; integer fields
  374.                 match only on decimal integers; mixed input fields
  375.                 match only alpha, uppercase alpha, or numeric input.
  376.             ****/
  377.  
  378.             switch ( templ_type )
  379.                 {
  380.                 case ALPHA:
  381.                 case UPPER:
  382.                     if ( isalpha(i) )
  383.                         templ_char = MIX_ALPHA;
  384.                     break;
  385.                 case INTGR:
  386.                     if ( isdigit(i) )
  387.                         templ_char = MIX_INTGR;
  388.                     break;
  389.                 case MIXED:
  390.                     templ_char =    isdigit(i)    ?    MIX_INTGR    :
  391.                                         isupper(i)    ?    MIX_UPPER    :
  392.                                         isalpha(i)    ?    MIX_ALPHA    :
  393.                                                             MIX_DELIM    ;
  394.                     break;
  395.                 }
  396.             DisplayStr[Pos] = templ_char;
  397.             Op |= templ_char;
  398.             if ( !display && templ_char != MIX_DELIM )
  399.                 OutStr[Pos] = Fill;
  400.             }                                        /* for(Pos)                                */
  401.         DisplayStr[Pos] = '\0';
  402.         if ( !Op )                                /* if no input slots,                */
  403.             {                                        /*  signal invalid template        */
  404.             *OutStr    =                            /*  for Error()                        */
  405.             i            = 0;
  406.             break;
  407.             }                                        /* else fall through to F_CHAR    */
  408.  
  409.     case F_CHAR:                                /* find first input slot            */
  410.  
  411.         i = -1;
  412.         while ( i < Width && !DisplayStr[++i] )
  413.             ;
  414.         if ( i >= Width )                        /* if no input slots                    */
  415.             i = 0;                                /* put cursor at beginning            */
  416.         break;
  417.  
  418.     case L_CHAR:                                /* find last input slot                */
  419.  
  420.         i = Width;
  421.         while ( i > 0 && !DisplayStr[--i] )
  422.             ;
  423.         break;
  424.  
  425.     case N_CHAR:                                /* find next input slot                */
  426.  
  427.         i = Pos;
  428.         while ( i < Width && !DisplayStr[++i] )
  429.             ;
  430.         if ( !DisplayStr[i] )
  431.             while ( i > 0 && !DisplayStr[--i] )
  432.                 ;
  433.         break;
  434.  
  435.     case P_CHAR:                                /* find previous input slot        */
  436.  
  437.         i = Pos;
  438.         while ( i > 0 && !DisplayStr[--i] )
  439.             ;
  440.         if ( !DisplayStr[i] )
  441.             while ( i < Width && !DisplayStr[++i] )
  442.                 ;
  443.         break;
  444.  
  445.     case N_WORD:                                /* find next input word                */
  446.  
  447.         i = Pos;
  448.         while ( i < Width &&  DisplayStr[++i] )
  449.             ;
  450.         while ( i < Width && !DisplayStr[++i] )
  451.             ;
  452.         if ( !DisplayStr[i] )
  453.             while ( i > 0 && !DisplayStr[--i] )
  454.                 ;
  455.         break;
  456.  
  457.     case P_WORD:                                /* find previous input word        */
  458.  
  459.         i = Pos;
  460.         while ( i > 0 && !DisplayStr[--i] )
  461.             ;
  462.         while ( i > 0 &&  DisplayStr[--i] )
  463.             ;
  464.         if ( !DisplayStr[i] )
  465.             while ( i < Width && !DisplayStr[++i] )
  466.                 ;
  467.         break;
  468.  
  469.     case S_WORD:                                /* find start of current word        */
  470.  
  471.         i = Pos;
  472.         while ( i > 0 && DisplayStr[--i] )
  473.             ;
  474.         ++i;
  475.         break;
  476.  
  477.     case E_WORD:                                /* find end of current word        */
  478.  
  479.         i = Pos;
  480.         while ( i < Width && DisplayStr[++i] )
  481.             ;
  482.         --i;
  483.         break;
  484.  
  485.     case T_WIPE:                                /* wipe to end of template            */
  486.  
  487.         for ( i = Pos ; Pos < Width ; Pos++ )
  488.             if ( DisplayStr[Pos] )
  489.                 OutStr[Pos] = Fill;
  490.         if ( !i )
  491.             i = TemplateFix( F_CHAR, 0 );
  492.         break;
  493.  
  494.     case -(T_WIPE):                            /* wipe to start of template        */
  495.  
  496.         for ( i = TemplateFix( F_CHAR, 0 ) ; Pos >= i ; Pos-- )
  497.             if ( DisplayStr[Pos] )
  498.                 OutStr[Pos] = Fill;
  499.         break;
  500.  
  501.     case T_STRIP:                                /* strip delimiters                    */
  502.  
  503.         for ( i = Pos = 0 ; Pos < Width ; Pos++ )
  504.             if ( DisplayStr[Pos] )
  505.                 OutStr[i++] = OutStr[Pos];
  506.         OutStr[i] = '\0';
  507.  
  508.     }                                                /* switch (Op)                            */
  509. return ( i );
  510. }                                                    /**** TemplateFix()                ****/
  511.  
  512. /**** EOF:  INTEMPL.C ****/
  513.